package com.intellif.aio.client;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.CountDownLatch;

/**
 * @author by mozping
 * @Classname AioClientHandler
 * @Description TODO
 * @Date 2019/4/23 10:10
 */
public class AioClientHandler implements CompletionHandler<Void, AioClientHandler>, Runnable {

    private String ip;
    private int port;
    //防止线程退出
    private CountDownLatch countDownLatch;
    private AsynchronousSocketChannel socketChannel;

    public AioClientHandler(String ip, int port) {
        this.ip = ip;
        this.port = port;
        try {
            socketChannel = AsynchronousSocketChannel.open();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        //通过CountDownLatch阻塞线程，避免线程马上退出
        countDownLatch = new CountDownLatch(1);
        socketChannel.connect(new InetSocketAddress(ip, port), null, this);
        try {
            countDownLatch.await();
            socketChannel.close();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    //连接成功，这个方法会被系统调用
    @Override
    public void completed(Void result, AioClientHandler attachment) {
        System.out.println("已经连接到服务端...");
    }

    //连接失败，这个方法会被系统调用
    @Override
    public void failed(Throwable exc, AioClientHandler attachment) {
        System.err.println("连接失败...");
        countDownLatch.countDown();
        try {
            socketChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public void sendMessage(String message) {
        byte[] bytes = message.getBytes();
        ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
        writeBuffer.put(bytes);
        writeBuffer.flip();
        //这个也是一个异步写的接口，方法会立即返回，系统完成写操作之后会回调，因此AioClientWriteHandler是需要实现CompletionHandler的
        //第1个writeBuffer，表示我们要发送给服务器的数据；
        //第2个writeBuffer，考虑到网络写有可能无法一次性将数据写完，需要进行多次网络写，
        //所以将writeBuffer作为附件传递给AioClientWriteHandler。
        socketChannel.write(writeBuffer, writeBuffer, new AioClientWriteHandler(socketChannel, countDownLatch));
    }
}
